<?php

namespace App\Service\Kms\Album;

use App\Jobs\Export\Export;
use App\Models\Common\OperateLogModel;
use App\Models\Kms\Album\AlbumMainModel;
use App\Models\Kms\Album\AlbumResourceModel;
use App\Models\Kms\User\KmsUser;
use App\Service\BaseService;
use App\Service\OpenShop\Feishu\ConfigService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;

class AlbumResourceService extends BaseService
{
    const BATCH_OPERATE_JOIN_RECYCLE    = 1;//1-批量加入回收站
    const BATCH_OPERATE_RESTORE_RECYCLE = 2;//2-批量从回收站恢复
    const BATCH_OPERATE_DELETE          = 3;//3-批量删除
    const BATCH_OPERATE_DOWNLOAD        = 4;//4-批量下载

    /**
     * @param object $params
     * @return array|void
     * @throws ValidationException
     */
    public static function list(object $params)
    {
        try {
            $albumResourceModel = AlbumResourceModel::query()
                                                    ->where("mid", $params->mid)
                                                    ->when($params->lastId > 0,
                                                        function (Builder $query) use ($params) {
                                                            $query->where("id", ">", $params->lastId);
                                                        })
                                                    ->when($params->lastTime == 0, function (Builder $query) {
                                                        $query->where("isDeleted", 0)
                                                              ->where("isInRecycleBin",
                                                                  AlbumResourceModel::IS_IN_RECYCLE_BIN_NO);
                                                    }, function ($query) use ($params) {
                                                        $query->where("updatedAt", ">=", $params->lastTime);
                                                    })->orderBy("id", "desc")->limit(200)->get();

            return [
                "list" => $albumResourceModel->toArray()
            ];
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源列表获取失败");
        }
    }

    /**
     * @param object $params
     * @return array|void
     * @throws ValidationException
     */
    public static function recycleBinList(object $params)
    {
        try {
            $pageSize = attributeGet($params, "pageSize", 10);
            $page     = attributeGet($params, "pageNum", 1);
            $paginate = AlbumResourceModel::query()
                                          ->where("mid", $params->mid)
                                          ->where("isDeleted", 0)
                                          ->where("isInRecycleBin", AlbumResourceModel::IS_IN_RECYCLE_BIN_YES)
                                          ->orderBy("id", "desc")
                                          ->paginate($pageSize, ["*"], "pageNum", $page);
            return [
                "list"     => $paginate->items(),
                "pageNum"  => $page,
                "pageSize" => $pageSize,
                "count"    => $paginate->total()
            ];
        } catch (\Exception $exception) {
            handleException($exception, null, null, "回收站资源列表获取失败");
        }
    }


    /**
     * @param object $params
     * @return array|void
     * @throws ValidationException
     */
    public static function upload(object $params)
    {
        try {
            $nowTime       = time();
            $getAmapDistrictJson = ConfigService::getAmapDistrictJson();
            $resourceGroup = collect($params->albumResourceGroup)->map(function ($v, $k) use (
                $getAmapDistrictJson,
                $nowTime,
                $params
            ) {
                list($provinceCode, $cityCode, $districtCode) = self::getProvinceCodeByAddress($v['addressPrefix'], $getAmapDistrictJson);
                $insertData = array_merge($v, [
                    "resourceNo"   => md5(
                        vsprintf(
                            "%s-%s-%s-%s-%s",
                            [
                                json_encode($params, JSON_UNESCAPED_UNICODE),
                                $nowTime,
                                request()->user()->rmsUserId,
                                $k,
                                random_int(100000, 999999)
                            ]
                        )
                    ),
                    "date"         => formatDateYmd($nowTime, "0000-00-00"),
                    "mid"          => $params->mid,
                    "createdAt"    => $nowTime,
                    "updatedAt"    => $nowTime,
                    "createdByUid" => request()->user()->rmsUserId,
                    "updatedByUid" => request()->user()->rmsUserId,
                    "provinceCode" => $provinceCode,
                    "cityCode"     => $cityCode,
                    "districtCode" => $districtCode,
                ]);
                return array_merge($insertData, ["id" => AlbumResourceModel::query()->insertGetId($insertData)]);
            })->values()->toArray();

            AlbumMainModel::setLastUpdateTime($nowTime, $params->mid);

            return [
                "resourceGroup" => $resourceGroup
            ];
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源上传失败");
        }
    }


    /**
     * @param object $params
     * @throws ValidationException
     */
    public static function joinRecycleBin(object $params)
    {
        try {
            $nowTime = time();
            if (
                !AlbumResourceModel::query()
                                   ->whereIn("id", $params->ridGroup)
                                   ->update([
                                       "isInRecycleBin" => AlbumResourceModel::IS_IN_RECYCLE_BIN_YES,
                                       "updatedAt"      => $nowTime,
                                       "updatedByUid"   => request()->user()->rmsUserId,
                                       "joinRecycleAt"  => $nowTime,
                                   ])
            ) {
                throw new \Exception("资源添加回收站失败");
            }

            AlbumMainModel::setLastUpdateTime($nowTime, $params->mid);
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源添加回收站失败");
        }
    }


    /**
     * @param object $params
     * @throws ValidationException
     */
    public static function resetRecycleBin(object $params)
    {
        try {
            $nowTime = time();
            if (
                !AlbumResourceModel::query()
                                   ->whereIn("id", $params->ridGroup)
                                   ->update([
                                       "updatedAt"      => $nowTime,
                                       "isInRecycleBin" => AlbumResourceModel::IS_IN_RECYCLE_BIN_NO,
                                       "updatedByUid"   => request()->user()->rmsUserId,
                                       "joinRecycleAt"  => 0,
                                   ])
            ) {
                throw new \Exception("资源取出回收站失败");
            }

            AlbumMainModel::setLastUpdateTime($nowTime, $params->mid);
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源取出回收站失败");
        }
    }

    /**
     * 批量还原回收站
     *
     * @param object $params
     * @throws ValidationException
     */
    public static function batchResetRecycleBin(object $params)
    {
        try {
            $nowTime = time();
            if (
                !AlbumResourceModel::query()
                                   ->where("mid", $params->mid)
                                   ->where("isDeleted", 0)
                                   ->where("isInRecycleBin", AlbumResourceModel::IS_IN_RECYCLE_BIN_YES)
                                   ->update([
                                       "updatedAt"      => $nowTime,
                                       "isInRecycleBin" => AlbumResourceModel::IS_IN_RECYCLE_BIN_NO,
                                       "updatedByUid"   => request()->user()->rmsUserId,
                                       "joinRecycleAt"  => 0,
                                   ])
            ) {
                throw new \Exception("资源取出回收站失败");
            }

            AlbumMainModel::setLastUpdateTime($nowTime, $params->mid);
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源取出回收站失败");
        }
    }


    /**
     * @param object $params
     * @throws ValidationException
     */
    public static function del(object $params)
    {
        try {
            $nowTime = time();
            if (
                !AlbumResourceModel::query()
                                   ->whereIn("id", $params->ridGroup)
                                   ->update([
                                       "deletedAt"    => $nowTime,
                                       "updatedAt"    => $nowTime,
                                       "isDeleted"    => 1,
                                       "updatedByUid" => request()->user()->rmsUserId,
                                   ])
            ) {
                throw new \Exception("资源删除失败");
            }
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源删除失败");
        }
    }


    /**
     * @param object $params
     * @throws ValidationException
     */
    public static function batchDel(object $params)
    {
        try {
            $nowTime = time();
            if (
                !AlbumResourceModel::query()
                                   ->where("mid", $params->mid)
                                   ->where("isInRecycleBin", AlbumResourceModel::IS_IN_RECYCLE_BIN_YES)
                                   ->update([
                                       "deletedAt"    => $nowTime,
                                       "updatedAt"    => $nowTime,
                                       "isDeleted"    => 1,
                                       "updatedByUid" => request()->user()->rmsUserId,
                                   ])
            ) {
                throw new \Exception("资源删除失败");
            }
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源删除失败");
        }
    }

    /**
     * @param string $url
     * @return string
     * @throws ValidationException
     */
    public static function genEncodeUrl(string $url): string
    {
        $encodeUrl = urlencode(self::encodeUrl($url));

        $appid = config('feishu.center.appID');

        return vsprintf("https://applink.feishu.cn/client/web_app/open?appId=%s&path=/operation/albumResource/page&mode=appCenter&resourceUrl=%s",
            [
                $appid,
                $encodeUrl
            ]);
    }

    /**
     * @param string $url
     * @return string|void
     * @throws ValidationException
     */
    public static function encodeUrl(string $url)
    {
        try {
            return Crypt::encryptString($url);
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源加密失败");
        }
    }

    /**
     * @param string $url
     * @return string|void
     * @throws ValidationException
     */
    public static function decodeUrl(string $url)
    {
        try {
            return Crypt::decryptString($url);
        } catch (\Exception $exception) {
            handleException($exception, null, null, "资源解密失败");
        }
    }

    /**
     * @param object $params
     * @return array
     */
    public static function resourceList(object $params): array
    {
        $pageNum  = attributeGet($params, "pageNum", 1);
        $pageSize = attributeGet($params, "pageSize", 10);
        $mid      = attributeGet(AlbumMainModel::query()->where("ownerUid", getRmsUserId())->first(), "id", 0);

        $paginate = AlbumResourceModel::query()
                                      ->where("mid", $mid)
                                      ->where("cruiseCheckStatus", $params->status)
                                      ->where("isDeleted", 0)
                                      ->where("isInRecycleBin", AlbumResourceModel::IS_IN_RECYCLE_BIN_NO)
                                      ->select(["id", "originalUrl as url", "mid", "type as isVideo"])
                                      ->orderBy("id", "desc")
                                      ->paginate($pageSize, ['*'], 'pageNum', $pageNum);

        return [
            "pageNum"  => $pageNum,
            "pageSize" => $pageSize,
            "total"    => $paginate->total(),
            "list"     => collect($paginate->items())->map(function (AlbumResourceModel $albumResourceModel) {
                switch ($albumResourceModel->isVideo) {
                    case AlbumResourceModel::TYPE_RESOURCE_1:
                        $albumResourceModel->isVideo = 0;
                        break;
                    case AlbumResourceModel::TYPE_RESOURCE_2:
                        $albumResourceModel->isVideo = 1;
                        break;
                }
                return $albumResourceModel;
            })->values()->toArray()
        ];
    }


    /**
     * 运营相册
     * @param int $isInRecycleBin
     * @param int $type
     * @param string $creatorUsername
     * @param int $provinceCode
     * @param int $cityCode
     * @param int $districtCode
     * @param string $addressSuffix
     * @param string $startTime
     * @param string $endTime
     * @param string $joinRecycleStartTime
     * @param string $joinRecycleEndTime
     * @param int $rmsUserId
     * @param int $pageSize
     * @param int $pageNum
     * @return array
     */
    public static function lists(
        int $isInRecycleBin,
        int $type,
        string $creatorUsername,
        int $provinceCode,
        int $cityCode,
        int $districtCode,
        string $addressSuffix,
        string $startTime,
        string $endTime,
        string $joinRecycleStartTime,
        string $joinRecycleEndTime,
        int $rmsUserId,
        int $pageSize,
        int $pageNum
    ): array
    {
        $paginator = AlbumResourceModel::query()
            ->when(
                $type, function ($query) use ($type) {
                $query->where('type', $type);//资源类型 0 - 图片 1 - 视频
            }
            )
            ->when(
                $rmsUserId, function ($query) use ($rmsUserId) {
                $query->where('createdByUid', $rmsUserId);//创建人
            }
            )
            ->when(
                $startTime && $endTime, function ($query) use ($startTime, $endTime) {
                $query->whereBetween("createdAt", [strtotime($startTime), strtotime($endTime)]);//创建时间
            }
            )
            ->when(
                $joinRecycleStartTime && $joinRecycleEndTime, function ($query) use ($joinRecycleStartTime, $joinRecycleEndTime) {
                $query->whereBetween("joinRecycleAt", [strtotime($joinRecycleStartTime), strtotime($joinRecycleEndTime)]);//加入回收站时间
            }
            )
            ->when(
                $creatorUsername, function ($query) use ($creatorUsername) {
                $rmsUserId = KmsUser::query()
                    ->orWhere("name", "like", "%{$creatorUsername}%")
                    ->orWhere("nickname", "like", "%{$creatorUsername}%")
                    ->get()->pluck('rmsUserId')->unique()->toArray();
                $query->whereIn("createdByUid", $rmsUserId);//创建人名称
            }
            )
            ->when(
                $provinceCode, function ($query) use ($provinceCode) {
                $query->where("provinceCode", $provinceCode);//省code
            }
            )
            ->when(
                $cityCode, function ($query) use ($cityCode) {
                $query->where("cityCode", $cityCode);//市code
            }
            )
            ->when(
                $districtCode, function ($query) use ($districtCode) {
                $query->where("districtCode", $districtCode);//区code
            }
            )
            ->when(
                $addressSuffix, function ($query) use ($addressSuffix) {
                $query->where("addressSuffix", "like", "%{$addressSuffix}%");//地址后缀 - 详细地址
            }
            )
            ->where('isInRecycleBin', $isInRecycleBin)//是否加入回收站 0 - 否 1 - 是
            ->where("isDeleted", 0)
            ->when(
                $isInRecycleBin, function ($query) use ($isInRecycleBin) {
                $query->orderByDesc('joinRecycleAt');//加入回收站时间排序
            }
            )
            ->orderByDesc('id')
            ->paginate($pageSize, ['*'], 'pageNum', $pageNum);

        $createdByUids = collect($paginator->items())->pluck('createdByUid')->unique()->toArray();
        $userInfos     = KmsUser::query()->whereIn("rmsUserId", $createdByUids)->get()->keyBy('rmsUserId')->toArray();

        $lists = $paginator->map(
            function (AlbumResourceModel $albumResourceModel) use ($userInfos) {
                $name     = $userInfos[$albumResourceModel->createdByUid]['name'] ?? "";
                $nickname = $userInfos[$albumResourceModel->createdByUid]['nickname'] ?? "";
                return [
                    'id'              => $albumResourceModel->id,
                    'type'            => $albumResourceModel->type,
                    'typeText'        => AlbumResourceModel::TYPE_GROUP[$albumResourceModel->type] ?? "",
                    'isInRecycleBin'  => $albumResourceModel->isInRecycleBin,
                    'originalUrl'     => $albumResourceModel->originalUrl,
                    'previewUrl'      => $albumResourceModel->previewUrl,
                    'createdAt'       => $albumResourceModel->createdAt ? formatDate($albumResourceModel->createdAt) : "",
                    'joinRecycleAt'   => $albumResourceModel->joinRecycleAt ? formatDate($albumResourceModel->joinRecycleAt) : "",
                    'createdByUid'    => $albumResourceModel->createdByUid,
                    'addressPrefix'   => $albumResourceModel->addressPrefix,
                    'addressSuffix'   => $albumResourceModel->addressSuffix,
                    'provinceCode'    => $albumResourceModel->provinceCode,
                    'cityCode'        => $albumResourceModel->cityCode,
                    'districtCode'    => $albumResourceModel->districtCode,
                    'creatorUsername' => $nickname . '(' . $name . ')',
                    'userAvatar'      => $userInfos[$albumResourceModel->createdByUid]['avatar'] ?? "",
                    'videoDuration'   => $albumResourceModel->videoDuration,
                    'resolutionRatio' => $albumResourceModel->resolutionRatio,
                ];
            }
        );

        return [
            'pageNum'   => $paginator->currentPage(),
            'pageSize'  => $paginator->perPage(),
            'pageCount' => ceil($paginator->total() / $paginator->perPage()),
            'count'     => $paginator->total(),
            'lists'     => $lists,
        ];
    }

    /**
     * 相册批量相关操作
     * @param array $ids
     * @param int $type
     * @param int $uid
     */
    public static function batchOperate(array $ids, int $type, int $uid)
    {
        $time = time();
        if ($type == self::BATCH_OPERATE_DOWNLOAD) {
            dispatch(
                (new Export(
                    '相册批量下载-' . $time,
                    Export::TYPE_ALBUM_RESOURCE, [
                        'data'   => [
                            'ids' => $ids,
                            'uid' => $uid,
                        ],
                        'userId' => $uid,
                    ]
                ))
            )->onQueue(Export::QUEUE_NAME);
//            self::batchDownloadAlbumResource($ids, $uid);
            return;
        }
        $update  = [
            'updatedAt'    => $time,
            'updatedByUid' => $uid
        ];
        $logName = '';
        switch ($type) {
            case self::BATCH_OPERATE_JOIN_RECYCLE://1-批量加入回收站
                $update['isInRecycleBin'] = AlbumResourceModel::IS_IN_RECYCLE_BIN_YES;
                $update['joinRecycleAt']  = $time;
                $logName                  = '运营相册批量加入回收站';
                break;
            case self::BATCH_OPERATE_RESTORE_RECYCLE://2-批量从回收站恢复
                $update['isInRecycleBin'] = AlbumResourceModel::IS_IN_RECYCLE_BIN_NO;
                $update['joinRecycleAt']  = 0;
                $logName                  = '运营相册批量从回收站恢复';
                break;
            case self::BATCH_OPERATE_DELETE://3-批量删除
                $update['isDeleted'] = 1;
                $update['deletedAt'] = $time;
                $logName             = '运营相册批量删除';
                break;
        }
        $updateRes = AlbumResourceModel::query()
            ->whereIn('id', $ids)
            ->where("isDeleted", 0)
            ->update($update);

        $data = [
            'ids'       => $ids,
            'type'      => $type,
            'uid'       => $uid,
            'updateRes' => $updateRes,
        ];

        // 操作日志
        OperateLogModel::add(
            OperateLogModel::BUSINESS_WEB_ALBUM_BATCH_OPERATE,
            0,
            0,
            $logName,
            json_encode($data),
            OperateLogModel::STATUS_OK,
            $uid,
        );
    }

    /**
     * 从地址获取省市区code
     * @param string $addressPrefix
     * @param array $getAmapDistrictJson
     * @return int[]
     */
    public static function getProvinceCodeByAddress(string $addressPrefix, array $getAmapDistrictJson = []): array
    {
        $provinceCode = $cityCode = $districtCode = 0;
        try {
            if ($addressPrefix && $addressPrefix != '--') {
                $addressPrefixArr = explode('-', $addressPrefix);
                if (!$getAmapDistrictJson) {
                    $getAmapDistrictJson = ConfigService::getAmapDistrictJson();
                }
                if ($getAmapDistrictJson && $addressPrefixArr) {
                    foreach ($getAmapDistrictJson as $v) {
                        if (isset($v['label']) && isset($addressPrefixArr[0]) &&
                            ($v['label'] == $addressPrefixArr[0] || mb_strpos($v['label'], $addressPrefixArr[0]) !== false)
                        ) {
                            $provinceCode = $v['value'];
                            foreach ($v['children'] as $children) {
                                if (isset($children['label']) && isset($addressPrefixArr[1]) &&
                                    ($children['label'] == $addressPrefixArr[1] || mb_strpos($children['label'], $addressPrefixArr[1]) !== false)
                                ) {
                                    $cityCode = $children['value'];
                                    foreach ($children['children'] as $child) {
                                        if (isset($addressPrefixArr[2]) && isset($child['label']) && $child['label'] == $addressPrefixArr[2]) {
                                            $districtCode = $child['value'];
                                            break;
                                        }
                                    }
                                    break;
                                }
                            }
                            break;
                        }
                    }
                }
            }
        } catch (\Exception $exception) {
            Log::error(
                "getProvinceCodeByAddress:", [
                'addressPrefix' => $addressPrefix,
                'msg'           => $exception->getMessage()
            ]
            );
        }
        return [$provinceCode, $cityCode, $districtCode];
    }

    /**
     * 批量下载图片
     * @param array $ids
     * @param int $uid
     * @return array
     */
    public static function batchDownloadAlbumResource(array $ids, int $uid): array
    {
        $res   = [];
        $count = AlbumResourceModel::query()
            ->whereIn('id', $ids)
            ->where("type", AlbumResourceModel::TYPE_RESOURCE_1)
            ->where("isDeleted", 0)
            ->count();
        if ($count) {
            $res = (new AlbumResourceZipDownloader)->fileResponse($ids, $uid);
        }
        Log::info(
            "batchDownloadAlbumResource:", [
                'ossInfo' => $res,
                'ids'     => $ids,
                'uid'     => $uid,
                'count'   => $count,
            ]
        );
        return $res;
    }
}
